package im.xz.cn.xiaip;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Logger;

public class join implements Listener {
    private static final Set<String> MAIN_LAND = new HashSet<>(Arrays.asList(
            "重庆", "北京", "上海", "天津",
            "河北", "山西", "辽宁", "吉林", "黑龙江", "江苏", "浙江", "安徽", "福建", "江西",
            "山东", "河南", "湖北", "湖南", "广东", "海南", "四川", "贵州", "云南", "陕西",
            "甘肃", "青海", "内蒙古", "广西", "西藏", "宁夏", "新疆"
    ));
    private static final Set<String> MAIN_CLOUD = new HashSet<>(Arrays.asList(
            "阿里", "腾讯", "华为", "百度", "京东", "亚马逊", "mazon", "google", "谷歌", "微软", "zure", "server", "cloud", "Cloud"
    ));
    private final Logger logger = Logger.getLogger(this.getClass().getName());

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        String playerIP = Objects.requireNonNull(player.getAddress()).getAddress().getHostAddress();

        if (isInternalIp(playerIP)) {
            return;
        }

        try {
            String location = getLocationFromIp(playerIP);
            if (location == null) {
                kickPlayer(player, "未能获取到你的地区信息");
                return;
            }

            boolean isInMainLand = containsAny(location, MAIN_LAND);
            boolean isInMainCloud = !isInMainLand && containsAny(location, MAIN_CLOUD);
            boolean isYunLocationButNotYunnan = location.contains("云") && !location.contains("云南")
                    && !location.contains("连云") && !location.contains("白云") && !location.contains("云浮");

            if (isInMainCloud || isYunLocationButNotYunnan) {
                logger.warning("[已阻止]" + player.getName() + " 地区是 " + location);
                kickPlayer(player, "请使用家庭IP进入服务器\n如果你认为这是一次误判，请联系管理员");
            } else if (isInMainLand) {
                logger.info(player.getName() + " 地区是 " + location);
            } else {
                logger.warning("[已阻止]" + player.getName() + " 地区是 " + location);
                kickPlayer(player, "此服务器仅对中国大陆地区开放\n如果你认为这是一次误判，请联系管理员");
            }
        } catch (IOException | InterruptedException e) {
            logger.severe("获取" + player.getName() + "的IP信息时发生异常");
            e.printStackTrace();
        }
    }

    private boolean isInternalIp(String ip) {
        if (ip == null || ip.isEmpty()) return false;
        String[] parts = ip.split("\\.");
        if (parts.length != 4) return false;
        try {
            int part0 = Integer.parseInt(parts[0]);
            int part1 = Integer.parseInt(parts[1]);
            return part0 == 10 ||
                    (part0 == 172 && part1 >= 16 && part1 <= 31) ||
                    ip.equals("127.0.0.1") ||
                    (part0 == 192 && part1 == 168);
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private String getLocationFromIp(String ip) throws IOException, InterruptedException {
        String url = "https://opendata.baidu.com/api.php?query=" + ip + "&co=&resource_id=6006&oe=utf8";
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
        JsonArray dataArray = jsonResponse.getAsJsonArray("data");
        if (dataArray != null && !dataArray.isEmpty()) {
            JsonObject firstDataObject = dataArray.get(0).getAsJsonObject();
            return firstDataObject.get("location").getAsString();
        }
        return null;
    }

    private boolean containsAny(String str, Set<String> set) {
        return set.stream().anyMatch(str::contains);
    }

    private void kickPlayer(Player player, String message) {
        player.kick(Component.text(message));
    }
}